package com.cloudpan.service.impl;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.amazonaws.HttpMethod;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudpan.common.CommonConstants;
import com.cloudpan.common.MinetypeConstant;
import com.cloudpan.common.MinioConstant;
import com.cloudpan.common.exception.GlobalExceptionHandler;
import com.cloudpan.entity.bo.TaskRecordBo;
import com.cloudpan.entity.param.InitTaskParam;
import com.cloudpan.entity.pojo.SysFileInfo;
import com.cloudpan.entity.pojo.SysUploadTask;
import com.cloudpan.entity.vo.TaskInfoVo;
import com.cloudpan.mapper.SysFileInfoMapper;
import com.cloudpan.mapper.SysUploadTaskMapper;
import com.cloudpan.mapper.SysUserInfoMapper;
import com.cloudpan.service.SysUploadTaskService;
import com.cloudpan.utils.ThumbnailUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 分片上传-分片任务记录 服务实现类
 * </p>
 *
 * @author Code Generator
 * @since 2024-01-15
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class SysUploadTaskServiceImpl extends ServiceImpl<SysUploadTaskMapper, SysUploadTask> implements SysUploadTaskService {

    private final AmazonS3 amazonS3;

    private final SysUploadTaskMapper sysUploadTaskMapper;

    private final SysFileInfoMapper fileInfoMapper;

    private final SysUserInfoMapper userInfoMapper;

    @Override
    public SysUploadTask getByIdentifier(String identifier) {
        return sysUploadTaskMapper.selectOne(new QueryWrapper<SysUploadTask>()
                .eq("file_identifier", identifier));
    }

    @Override
    public String uploadfile(MultipartFile file, InitTaskParam param) {
//        if (file.getSize() > 5 * 1024 * 1024){
//            throw new GlobalExceptionHandler("文件大小大于5M,无法上传该文件,请调用分片上传的接口~");
//        }
        InputStream inputStream = null;
        String thumbnailkey = null;
        PutObjectRequest putObjectRequest = null;
        String paramName = file.getOriginalFilename();
        String suffix = paramName.substring(paramName.lastIndexOf(".") + 1);
        String key = StrUtil.format("{}.{}",  UUID.fastUUID().toString(true), suffix);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(file.getContentType());
        log.info("@@@@@@@@@@@@@@@@@@::::上传的文件类型:" + file.getContentType());
        try {
            //上传文件
            inputStream = file.getInputStream();
            putObjectRequest = new PutObjectRequest(param.getUserId()
                    ,key,inputStream,objectMetadata);
            amazonS3.putObject(putObjectRequest);
            //上传完文件后生成缩略图
            InputStream thumbnailType = ThumbnailUtils.getThumbnailType(suffix, file.getInputStream());
            log.info("@@@@@@@@@@@@@@@@@@:" + thumbnailType.toString());
            thumbnailkey = ThumbnailUtils.getThumbnailPath(key.substring(0,key.lastIndexOf(".")));
            objectMetadata.setContentType("image/png");
            log.info("@@@@@@@@@@@@@@@@@@:" + thumbnailkey);
            amazonS3.putObject(new PutObjectRequest("thumbnails",thumbnailkey,thumbnailType,objectMetadata));
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        SysFileInfo taskFile = new SysFileInfo();
        taskFile.setFileName(file.getOriginalFilename());
        taskFile.setFileMd5(param.getIdentifier());
        taskFile.setFileSize(file.getSize());
        taskFile.setUserId(param.getUserId());
        taskFile.setFileUrl(getPath(param.getUserId(),key));
        taskFile.setFilePid(param.getFilePid());
        taskFile.setFileCategory(MinetypeConstant.getFileCategory(paramName));
        taskFile.setFileCover(getThumbnailPath(thumbnailkey));
        taskFile.setFolderType(CommonConstants.FOLDERTYPE_ZERO);
        taskFile.setStatus("0");
        taskFile.setObjectKey(key);
        //保存用户上传的文件元数据信息
        fileInfoMapper.insert(taskFile);
        //更新用户的存储空间
        userInfoMapper.useTotalSpace(param);

        return getPath(param.getUserId(),key);
    }

    @Override
    public TaskInfoVo initTask(InitTaskParam param) {
        String fileName = param.getFileName();
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        String key = StrUtil.format("{}.{}",  UUID.fastUUID().toString(true), suffix);
        String contentType = MediaTypeFactory.getMediaType(key)
                .orElse(MediaType.APPLICATION_OCTET_STREAM).toString();
        log.info("文件类型:{}",contentType);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(contentType);
        InitiateMultipartUploadRequest initiateMultipartUploadRequest =
                new InitiateMultipartUploadRequest(param.getUserId(), key).withObjectMetadata(objectMetadata);
        InitiateMultipartUploadResult initiateMultipartUploadResult = amazonS3
                .initiateMultipartUpload(initiateMultipartUploadRequest);
        String uploadId = initiateMultipartUploadResult.getUploadId();
        SysUploadTask task = new SysUploadTask();
        task.setId(null);
        int chunkNum = (int) Math.ceil(param.getTotalSize() * 1.0 / param.getChunkSize());
        task.setBucketName(param.getUserId());
        task.setChunkNum(chunkNum);
        task.setChunkSize(param.getChunkSize());
        task.setFileIdentifier(param.getIdentifier());
        task.setFileName(fileName);
        task.setObjectKey(key);
        task.setUploadId(uploadId);
        sysUploadTaskMapper.insert(task);
        return new TaskInfoVo().setFinished(false)
                .setTaskRecord(TaskRecordBo.convertFromEntity(task))
                .setPath(getPath(param.getUserId(), key));
    }

    @Override
    public String getPath(String bucket, String objectKey) {
        return "http://192.168.18.10:9000/" + bucket + "/" + objectKey;
    }

    @Override
    public String getThumbnailPath(String objectKey) {
        return "http://192.168.18.10:9000/thumbnails/" + objectKey;
    }

    @Override
    public TaskInfoVo getTaskInfo(String identifier) {
        SysUploadTask task = getByIdentifier(identifier);
        if (task == null) {
            return null;
        }
        TaskInfoVo result = new TaskInfoVo()
                .setFinished(true)
                .setTaskRecord(TaskRecordBo.convertFromEntity(task))
                .setPath(getPath(task.getBucketName(), task.getObjectKey()));

        boolean doesObjectExist = amazonS3.doesObjectExist(task.getBucketName(), task.getObjectKey());
        if (!doesObjectExist) {
            // 未上传完，返回已上传的分片
            ListPartsRequest listPartsRequest = new ListPartsRequest(task.getBucketName(), task.getObjectKey(), task.getUploadId());
            PartListing partListing = amazonS3.listParts(listPartsRequest);
            result.setFinished(false).getTaskRecord().setExitPartList(partListing.getParts());
        }
        return result;
    }

    @Override
    public void merge(String identifier) {
        SysUploadTask task = getByIdentifier(identifier);
        if (task == null) {
            throw new GlobalExceptionHandler("分片任务不存在");
        }
        ListPartsRequest listPartsRequest = new ListPartsRequest(task.getBucketName(), task.getObjectKey(), task.getUploadId());
        PartListing partListing = amazonS3.listParts(listPartsRequest);
        List<PartSummary> parts = partListing.getParts();
        if (!task.getChunkNum().equals(parts.size())) {
            // 已上传分块数量与记录中的数量不对应，不能合并分块
            throw new GlobalExceptionHandler("分片缺失，请重新上传");
        }
        CompleteMultipartUploadRequest completeMultipartUploadRequest =
                new CompleteMultipartUploadRequest()
                        .withUploadId(task.getUploadId())
                        .withKey(task.getObjectKey())
                        .withBucketName(task.getBucketName())
                        .withPartETags(parts.stream()
                                .map(partSummary -> new PartETag(partSummary.getPartNumber(), partSummary.getETag()))
                                .collect(Collectors.toList()));
        amazonS3.completeMultipartUpload(completeMultipartUploadRequest);
        //合并完分片才算真正的上传完成，保存用户的信息存储文件
    }


    @Override
    public String genPreSignUploadUrl(String bucket, String objectKey, Map<String, String> params) {
        Date currentDate = new Date();
        Date expireDate = DateUtil.offsetMillisecond(currentDate, MinioConstant.PRE_SIGN_URL_EXPIRE.intValue());
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, objectKey)
                .withExpiration(expireDate).withMethod(HttpMethod.PUT);
        if (params != null) {
            params.forEach(request::addRequestParameter);
        }
        URL preSignedUrl = amazonS3.generatePresignedUrl(request);
        return preSignedUrl.toString();
    }

}
